import { BaseRequest } from '@/core';
import { buildFullPath, merge } from '@/core/util';
import { xhrRequest } from '@/core/xhr';
import { CallbackResult, RequestConfig, ResponseResult } from './type';
import { getCredentials } from './util';
import { request } from '@tarojs/taro';

class Request extends BaseRequest<RequestConfig, ResponseResult> {
    protected dispatchRequest(config: RequestConfig): Promise<ResponseResult> {
        return new Promise((resolve, reject) => {
            const {
                baseUrl,
                headers,
                credentials,
                withCredentials,
                useXhr = false,
                url = '',
                responseType = 'text',
                dataType = 'json',
                params = {},
                method = 'GET',
                ...options
            } = merge({}, { ...config }) as RequestConfig;
            const newUrl = buildFullPath(url, baseUrl);

            // Taro 未对 @taro/taro 进行模块化处理， 所以这里进行解构使用
            // 传送门 https://github.com/NervJS/taro/pull/17755
            try {
                if (useXhr) {
                    xhrRequest({
                        method,
                        url: newUrl,
                        params,
                        headers,
                        responseType,
                        dataType,
                        withCredentials,
                        timeout: options.timeout,
                        config
                    })
                        .then((response: Record<string, any>) => {
                            const { data, status, statusText } = { ...response };
                            resolve({
                                data,
                                status,
                                headers,
                                statusText,
                                config
                            });
                        })
                        .catch((xhrError) => {
                            console.error(`XHR fallback failed: ${newUrl}`, xhrError);
                            reject({
                                ...xhrError,
                                url: newUrl,
                                config
                            });
                        });
                } else {
                    request({
                        method,
                        dataType,
                        url: newUrl,
                        data: params,
                        responseType,
                        header: headers,
                        credentials: getCredentials(withCredentials, credentials),
                        success(response: Record<string, any>) {
                            const { data, statusCode, errMsg } = { ...response };
                            resolve({
                                data,
                                status: statusCode,
                                headers,
                                statusText: errMsg,
                                config
                            });
                        },
                        fail(error: CallbackResult) {
                            console.warn(
                                `Taro request failed: ${newUrl}, falling back to XHR`,
                                error
                            );
                            const enhancedError = {
                                error,
                                config,
                                url: newUrl,
                                message: error.errMsg || 'Unknown error',
                                timestamp: new Date().toISOString()
                            };
                            reject(enhancedError);
                        },
                        ...options
                    } as any);
                }
            } catch (e) {
                console.error(`Exception during request: ${newUrl}`, e);
                reject({
                    error: e,
                    config,
                    message: 'Exception during request setup',
                    timestamp: new Date().toISOString()
                });
            }
        });
    }
}

export default Request;
